/************************************************************************
                                                                     
   Xceed Ultimate ListBox for Silverlight                                                                                                                                            
   Copyright (C) 2010 Xceed Software Inc.    
                                                                     
   This program is provided to you under the terms of the GNU General Public  
   License version 2 as published by the Free Software Foundation. 
        
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY, without even the implied warranty of 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along 
   with this program, if not, write to the Free Software Foundation, Inc., 
   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

   This program can be provided to you by Xceed Software Inc. under a
   proprietary commercial license agreement for use in non-Open Source
   projects. Visit Xceed.com to find the commercial edition of 
   Xceed Ultimate ListBox for Silverlight.                                    
                                                                      
 **********************************************************************/

//using System;
//using System.Collections.Generic;
//using System.Diagnostics;
//using System.Linq;

//namespace Xceed.Silverlight.Data
//{
//  // NEW VERSION OF ReactiveAsyncWithCachingEnumerator.

//  // This class is derived from CachingEnumerator instead of being added as
//  // a distinct item in the enumerator chain, avoiding unecessary indirection, because 
//  // it is tightly coupled with the CachingEnumerator and the ReactiveAsyncDataEnumerator.
//  /// <summary>
//  /// This enumerator cache fetched items from the source enumerator.
//  /// It keeps a limited amount of records that have been fetched and that
//  /// are in a contiguous sequence before and/or after the actual child enumerator
//  /// position. It will return the cache version of the data if requested data
//  /// fall within the cache.
//  /// Cache will be cleared if source enumerator is moved in a manner that the
//  /// its current position is non-contiguous with the cache content.
//  /// </summary>
//  internal class ReactiveWithCacheEnumerator : CacheEnumerator<DataPath>
//  {
//    internal ReactiveWithCacheEnumerator( 
//      int cacheSize, 
//      ReactiveHelper reactiveHelper, 
//      
//      GroupHelper groupHelper,
//      IAsyncEnumerator<DataPath> subEnumerator, 
//      ThrottlingHandler throttlingHandler )
//      : base( cacheSize, reactiveHelper, null )
//    {
//      ReactiveOverrideClass reactiveOverride = new ReactiveOverrideClass(
//                                 this,
//                                 subEnumerator,
//                                 reactiveHelper.DataItemFactory,
//                                 throttlingHandler );

//      this.ChildEnumerator = new SyncToAsyncEnumerator<DataPath>( reactiveOverride );

//      reactiveOverride.HasPendingRequestsChanged += new EventHandler( OnHasPendingRequestsChanged );
//      reactiveOverride.OperationCompleted += new EventHandler<OperationCompletedEventArgs<DataPath>>( OnOperationCompleted );
//    }


//    #region ReactiveDataEnumerator Property

//    private ReactiveOverrideClass ReactiveDataEnumerator
//    {
//      get
//      {
//        
//        return ( ReactiveOverrideClass )
//            ( ( SyncToAsyncEnumerator<DataPath> )
//               this.ChildEnumerator ).ChildEnumerator;
//      }
//    }

//    #endregion ReactiveDataEnumerator Property

//    #region DataItemFactory Property

//    internal DataItemFactory<DataPath> DataItemFactory
//    {
//      get
//      {
//        return this.ReactiveDataEnumerator.DataItemFactory;
//      }
//    }

//    #endregion DataItemFactory Property

//    #region ReactiveHelper Property

//    internal ReactiveHelper ReactiveHelper
//    {
//      get
//      {
//        return ( ReactiveHelper )this.DataHelper;
//      }
//    }

//    #endregion ReactiveHelper Property


//    #region OperationCompleted Event

//    internal event EventHandler<OperationCompletedEventArgs<DataPath>> OperationCompleted;

//    private void OnOperationCompleted( object sender, OperationCompletedEventArgs<DataPath> e )
//    {
//      if(e.Replacements != null)
//      {
//        foreach(Tuple<DataPath,DataPath> replacement in e.Replacements)
//        {
//          this.ChildDataReplaced( replacement.Item1, replacement.Item2 );
//        }
//      }

//      
//      if( e.Deletions != null && e.Deletions.Count > 0 )
//      {
//        int minIndex = this.CachedItems.Count;
//        int maxIndex = -1;

//        foreach( DataPath path in e.Deletions )
//        {
//          int pathIndex = this.CachedItems.IndexOf( path );
//          if( pathIndex >= 0 )
//          {
//            minIndex = Math.Min( minIndex, pathIndex );
//            maxIndex = Math.Max( maxIndex, pathIndex );
//          }
//        }

//        if( e.Operation.EndPositionObject.IsBeforeFirst )
//        {
//          
//          
//          
//          if( maxIndex >= 0 )
//          {
//            this.CachedItems.RemoveRange( 0, maxIndex + 1 );
//            this.UpdateCountInformation( new RelativeOffset( 1, ReferencePoint.BeforeFirst ), e.Operation.TotalCount );
//          }
//        }
//        else
//        {
//          Debug.Assert( e.Operation.EndPositionObject.IsAfterLast );

//          
//          
//          
//          if( minIndex < this.CachedItems.Count )
//          {
//            this.CachedItems.RemoveRange( minIndex, this.CachedItems.Count - minIndex );
//            this.UpdateCountInformation( new RelativeOffset( minIndex, ReferencePoint.AfterLast ), e.Operation.TotalCount );
//          }
//        }
//      }
//      else
//      {
//        EstimateInt64 notNeeded;
//        RelativeOffset firstItemOffset;

//        this.ExtractIndexes( e.Operation, out notNeeded, out firstItemOffset );
//        this.UpdateCountInformation( firstItemOffset, e.Operation.TotalCount );
//      }

//      if( this.OperationCompleted != null )
//      {
//        this.OperationCompleted( this, e );
//      }
//    }

//    #endregion OperationCompleted Event

//    public void SetNextItemTemplate( DataPath template )
//    {
//      //A "null" itemTemplate is a valid template. That
//      //is why there is a bool flag
//      //to hold the "validity" of the item template value.
//      m_useCacheNextItemTemplate = true;
//      m_cacheNextItemTemplate = template;
//    }

//    public void SetPreviousItemTemplate( DataPath template )
//    {
//      //A "null" itemTemplate is a valid template. That
//      //is why there is a bool flag
//      //to hold the "validity" of the item template value.
//      m_useCachePreviousItemTemplate = true;
//      m_cachePreviousItemTemplate = template;
//    }

//    protected override JumpMoveAndFetchAsyncResult BeginChildJumpMoveAndFetch( 
//      JumpMoveAndFetchParameters parameters, 
//      AsyncCallback userCallback, 
//      object asyncState )
//    {
//      //Check if the data will be appended to the cache.
//      int queryDirection = ( parameters.ExpectedMoveCount > 0 ) 
//                             ? DataUtils.GetUnit( parameters.ExpectedMoveCount ) 
//                             : DataUtils.GetUnit( parameters.ExpectedFetchCount );
//      bool fetchCacheNext = false;
//      bool fetchCachePrevious = false;

//      if( this.CachedItems.Count == 0 )
//      {
//        fetchCacheNext = ( queryDirection > 0 );
//        fetchCachePrevious = ( queryDirection < 0 );
//      }
//      else
//      {
//        Nullable<int> sourcePositionIndex = this.FindSourcePositionIndex( 
//          parameters.SourcePosition, 
//          parameters.ExpectedMoveCount, 
//          parameters.ExpectedFetchCount );

//        if( sourcePositionIndex.HasValue )
//        {
//          long fetchStartIndex = sourcePositionIndex.Value + parameters.ExpectedMoveCount;
//          long fetchEndIndex = fetchStartIndex + ( parameters.ExpectedFetchCount - DataUtils.GetUnit( parameters.ExpectedFetchCount ) );

//          if( fetchStartIndex >= 0 && fetchStartIndex < this.CachedItems.Count )
//            throw new DataInternalException();//Not expecting a child fetch starting within the bound of the cache.

//          fetchCacheNext = ( fetchStartIndex <= this.CachedItems.Count ) && ( fetchEndIndex >= this.CachedItems.Count )
//                        || ( fetchStartIndex >= this.CachedItems.Count ) && ( fetchEndIndex <= this.CachedItems.Count );

//          fetchCachePrevious = ( fetchStartIndex <= 0 ) && ( fetchEndIndex >= 0 )
//                            || ( fetchStartIndex >= 0 ) && ( fetchEndIndex <= 0 );
//        }
//      }

//      //In theses case we consider the m_cacheNextItemTemplate and m_cachePreviousItemTemplate values
//      if( fetchCacheNext && m_useCacheNextItemTemplate )
//      {
//        Debug.Assert( !fetchCachePrevious );

//        //Cache will be append this data to the end of cache.
//        this.ReactiveDataEnumerator.SetItemTemplateOverride( m_cacheNextItemTemplate );
//      }
//      else if( fetchCachePrevious && m_useCachePreviousItemTemplate )
//      {
//        Debug.Assert( !fetchCacheNext );

//        //Cache will be append this data to the begin of cache.
//        this.ReactiveDataEnumerator.SetItemTemplateOverride( m_cachePreviousItemTemplate );
//      }

//      JumpMoveAndFetchAsyncResult asyncResult = base.BeginChildJumpMoveAndFetch( 
//                                                  parameters, 
//                                                  userCallback, 
//                                                  asyncState );

//      //The ItemOverride can now be cleared
//      m_useCacheNextItemTemplate = false;
//      m_useCachePreviousItemTemplate = false;
//      m_cacheNextItemTemplate = null;
//      m_cachePreviousItemTemplate = null;

//      this.ReactiveDataEnumerator.ClearItemTemplateOverride();

//      return asyncResult;
//    }

//    internal override bool GetModifiedItemToRemove( DataPath modifiedItem, out DataPath itemToRemove, out Nullable<bool> itemExist )
//    {
//      int index = this.CachedItems.IndexOf( modifiedItem );

//      if( index == -1 )
//      {
//        
//        
//        
//        for( int i = 0; i < this.CachedItems.Count; i++ )
//        {
//          if( object.Equals( this.CachedItems[ i ].LastChild, modifiedItem.LastChild ) )
//          {
//            index = i;
//            break;
//          }
//        }
//      }

//      if( index >= 0 )
//      {
//        itemToRemove = this.CachedItems[ index ];
//        itemExist = true;
//        return true;
//      }
//      else
//      {
//        itemToRemove = null;
//        itemExist = null;
//        return false;
//      }
//    }

//    internal override bool GetModifiedItemToAdd( DataPath modifiedItem, out DataPath itemToAdd, out Nullable<bool> itemExist )
//    {
//      
//      
//      

//      bool returnValue;

//      int collapsedDepth = this.ReactiveHelper.GroupHelper.GroupHandler.GetCollapsedDepth( modifiedItem );

//      if( collapsedDepth == 0 )
//      {
//        itemToAdd = modifiedItem;
//        itemExist = false;
//        returnValue = true;
//      }
//      else
//      {
//        itemToAdd = modifiedItem.CreateAncestorPath( collapsedDepth );

//        // Check if the collapsed version of the item is already in cache.
//        // If it is, dont add it twice !
//        if( this.CachedItems.Contains( itemToAdd ) )
//        {
//          itemToAdd = null;
//          itemExist = true;
//          returnValue = false;
//        }
//        else
//        {
//          //Get the group count in order to know if the item existed before
//          itemExist = null;
//          returnValue = true;
//        }
//      }

//      return returnValue;
//    }

//    protected override Nullable<int> FindSourcePositionIndex( 
//      SourcePosition sourcePosition, 
//      long expectedMoveCount,
//      int expectedFetchCount )
//    {
//      if( sourcePosition is DummyPosition<DataPath> )
//      {
//        DataPath item;
//        long offset;
//        SourcePosition position;
//        bool approximateOffset;
//        DummyPosition<DataPath> dummyPosition = ( DummyPosition<DataPath> )sourcePosition;
//        Func<DataPath, SourcePosition> positionResolver;

//        if( DataUtils.ResolvePosition( dummyPosition, false, out position, out item, out offset, out approximateOffset, out positionResolver ) )
//        {
//          int index = this.CachedItems.IndexOf( item );

//          return ( index != -1 )
//                   ? Convert.ToInt32( index + offset )
//                   : ( Nullable<int> )null;
//        }
//        else
//        {
//          Nullable<int> positionIndex = base.FindSourcePositionIndex( position, expectedMoveCount, expectedFetchCount );

//          return ( positionIndex.HasValue )
//                   ? Convert.ToInt32( positionIndex.Value + offset )
//                   : ( Nullable<int> )null;
//        }
//      }
//      else if( sourcePosition is DependentPosition<DataPath> )
//      {
//        Debug.Assert( ( ( DependentPosition<DataPath> )sourcePosition ).PositionResolver != null, 
//          "If this is raised, a optimisation could be done by seaching the cache for the item." );

//        return null;
//      }

//      return base.FindSourcePositionIndex( sourcePosition, expectedMoveCount, expectedFetchCount );
//    }

//    protected override void Dispose( bool disposing )
//    {
//      if( disposing )
//      {
//        ReactiveEnumerator<DataPath> reactiveEnumerator = this.ReactiveDataEnumerator;

//        reactiveEnumerator.HasPendingRequestsChanged -= new EventHandler( OnHasPendingRequestsChanged );
//        reactiveEnumerator.OperationCompleted -= new EventHandler<OperationCompletedEventArgs<DataPath>>( OnOperationCompleted );
//      }

//      base.Dispose( disposing );
//    }

//    private void OnHasPendingRequestsChanged( object sender, EventArgs e )
//    {
//      if( this.HasPendingRequestsChanged != null )
//      {
//        this.HasPendingRequestsChanged( this, e );
//      }
//    }


//    #region IPendingRequests Members

//    public bool HasPendingRequests
//    {
//      get
//      {
//        return this.ReactiveDataEnumerator.HasPendingRequests;
//      }
//    }

//    public event EventHandler HasPendingRequestsChanged;

//    #endregion //IPendingRequests Members


//    #region Private Fields

//    private DataPath m_cacheNextItemTemplate;
//    private DataPath m_cachePreviousItemTemplate;
//    private bool m_useCacheNextItemTemplate;
//    private bool m_useCachePreviousItemTemplate;

//    #endregion Private Fields


//    #region Private ReactiveOverrideClass Nested Type

//    private class ReactiveOverrideClass : ReactiveEnumerator<DataPath>
//    {
//      internal ReactiveOverrideClass(
//        ReactiveWithCacheEnumerator cachedReactive,
//        IAsyncEnumerator<DataPath> subEnumerator,
//        DataItemFactory<DataPath> dataItemFactory,
//        ThrottlingHandler throttlingHandler )
//        : base( subEnumerator, dataItemFactory, throttlingHandler )
//      {
//        m_cachedReactive = cachedReactive;
//      }

//      public void SetItemTemplateOverride( DataPath itemTemplate )
//      {
//        //A "null" itemTemplate is a valid "override". That
//        //is why there is a "m_useItemTemplateOverride" bool flag
//        //to hold the "validity" of the m_itemTemplateOverride value.
//        m_itemTemplateOverride = itemTemplate;
//        m_useItemTemplateOverride = true;
//      }

//      public void ClearItemTemplateOverride()
//      {
//        m_itemTemplateOverride = null;
//        m_useItemTemplateOverride = false;
//      }

//      protected override DataPath CreateDummyItem( DataPath templateItem )
//      {
//        if( m_useItemTemplateOverride )
//        {
//          return base.CreateDummyItem( m_itemTemplateOverride );
//        }
//        else
//        {
//          return base.CreateDummyItem( templateItem );
//        }
//      }

//      protected override bool ShouldPerformFetch( DataPath item )
//      {
//        // If the dummy for the item that is about to be fetched is no longer in the list
//        // of dummies of the cache, it means that the item is no longer needed.
//        return m_cachedReactive.CachedItems.Contains( item );
//      }

//      protected override bool DummyDependOn( DataPath doesThisDummy, DataPath dependOnThisOne )
//      {
//        return ( doesThisDummy.IsAncestorOf( dependOnThisOne )
//          || base.DummyDependOn( doesThisDummy, dependOnThisOne ) );
//      }

//      private ReactiveWithCacheEnumerator m_cachedReactive;
//      private DataPath m_itemTemplateOverride;
//      private bool m_useItemTemplateOverride;
//    }

//    #endregion Private ReactiveOverrideClass Nested Type
//  }
//}
